home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1997 / MacHack 1997.toast / Hacks / Hacks ’96 / VideoFolder 1.0a / Source / MoreFiles 1.4.1 / IterateDirectory.c < prev    next >
Text File  |  1995-12-21  |  6KB  |  184 lines

  1. /*
  2. **    IterateDirectory: File Manager directory iterator routines.
  3. **
  4. **    by Jim Luther
  5. **
  6. **    File:        IterateDirectory.c
  7. **
  8. **    Copyright © 1995 Jim Luther
  9. **    All rights reserved.
  10. **
  11. **    You may incorporate this sample code into your applications without
  12. **    restriction, though the sample code has been provided "AS IS" and the
  13. **    responsibility for its operation is 100% yours.
  14. **
  15. **    IterateDirectory is designed to drop into the MoreFiles sample code
  16. **    library I wrote while in Apple Developer Technical Support
  17. */
  18.  
  19. #include <Types.h>
  20. #include <Errors.h>
  21. #include <Files.h>
  22. #include "MoreFilesExtras.h"
  23. #include "IterateDirectory.h"
  24.  
  25. /*
  26. **    Type definitions
  27. */
  28.  
  29. /* The IterateGlobals structure is used to minimize the amount of
  30. ** stack space used when recursively calling IterateDirectoryLevel
  31. ** and to hold global information that might be needed at any time.
  32. */
  33. #if PRAGMA_ALIGN_SUPPORTED
  34. #pragma options align=mac68k
  35. #endif
  36. struct IterateGlobals
  37. {
  38.     IterateFilterProcPtr    iterateFilter;    /* pointer to IterateFilterProc */
  39.     CInfoPBRec                cPB;            /* the parameter block used for PBGetCatInfo calls */
  40.     Str63                    itemName;        /* the name of the current item */
  41.     OSErr                    result;            /* temporary holder of results - saves 2 bytes of stack each level */
  42.     Boolean                    quitFlag;        /* set to true if filter wants to kill interation */
  43.     unsigned short            maxLevels;        /* Maximum levels to iterate through */
  44.     unsigned short            currentLevel;    /* The current level IterateLevel is on */
  45.     void                    *yourDataPtr;    /* A pointer to caller data the filter may need to access */
  46. };
  47. #if PRAGMA_ALIGN_SUPPORTED
  48. #pragma options align=reset
  49. #endif
  50.  
  51. typedef struct IterateGlobals IterateGlobals;
  52. typedef IterateGlobals *IterateGlobalsPtr;
  53.  
  54. /*****************************************************************************/
  55.  
  56. /*    Static Prototype */
  57.  
  58. static    void    IterateDirectoryLevel(long dirID,
  59.                                       IterateGlobalsPtr theGlobals);
  60.  
  61. /*****************************************************************************/
  62.  
  63. /*
  64. **    Functions
  65. */
  66.  
  67. static    void    IterateDirectoryLevel(long dirID,
  68.                                       IterateGlobalsPtr theGlobals)
  69. {
  70.     if ( (theGlobals->maxLevels == 0) ||                        /* if maxLevels is zero, we aren't checking levels */
  71.          (theGlobals->currentLevel < theGlobals->maxLevels) )    /* if currentLevel < maxLevels, look at this level */
  72.     {
  73.         short index = 1;
  74.         
  75.         ++theGlobals->currentLevel;    /* go to next level */
  76.         
  77.         do
  78.         {    /* Isn't C great... What I'd give for a "WITH theGlobals DO" about now... */
  79.         
  80.             /* Get next source item at the current directory level */
  81.             
  82.             theGlobals->cPB.dirInfo.ioFDirIndex = index;
  83.             theGlobals->cPB.dirInfo.ioDrDirID = dirID;
  84.             theGlobals->result = PBGetCatInfoSync((CInfoPBPtr)&theGlobals->cPB);        
  85.     
  86.             if ( theGlobals->result == noErr )
  87.             {
  88.                 /* Call the IterateFilterProc */
  89.                 CallIterateFilterProc(theGlobals->iterateFilter, &theGlobals->cPB, &theGlobals->quitFlag, theGlobals->yourDataPtr);
  90.                 
  91.                 /* Is it a directory? */
  92.                 if ( (theGlobals->cPB.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  93.                 {
  94.                     /* We have a directory */
  95.                     if ( !theGlobals->quitFlag )
  96.                     {
  97.                         /* Dive again if the IterateFilterProc didn't say "quit" */
  98.                         IterateDirectoryLevel(theGlobals->cPB.dirInfo.ioDrDirID, theGlobals);
  99.                     }
  100.                 }
  101.             }
  102.             
  103.             ++index; /* prepare to get next item */
  104.         } while ( (theGlobals->result == noErr) && (!theGlobals->quitFlag) ); /* time to fall back a level? */
  105.         
  106.         if ( theGlobals->result == fnfErr )    /* fnfErr is OK - it only means we hit the end of this level */
  107.             theGlobals->result = noErr;
  108.             
  109.         --theGlobals->currentLevel;    /* return to previous level as we leave */
  110.     }
  111. }
  112.  
  113. /*****************************************************************************/
  114.  
  115. pascal    OSErr    IterateDirectory(short vRefNum,
  116.                                  long dirID,
  117.                                  StringPtr name,
  118.                                  unsigned short maxLevels,
  119.                                  IterateFilterProcPtr iterateFilter,
  120.                                  void *yourDataPtr)
  121. {
  122.     IterateGlobals    theGlobals;
  123.     OSErr            result;
  124.     long            theDirID;
  125.     short            theVRefNum;
  126.     Boolean            isDirectory;
  127.     
  128.     /* Make sure there is a IterateFilter */
  129.     if ( iterateFilter != NULL )
  130.     {
  131.         /* Get the real directory ID and make sure it is a directory */
  132.         result = GetDirectoryID(vRefNum, dirID, name, &theDirID, &isDirectory);
  133.         if ( result == noErr )
  134.         {
  135.             if ( isDirectory == true )
  136.             {
  137.                 /* Get the real vRefNum */
  138.                 result = DetermineVRefNum(name, vRefNum, &theVRefNum);
  139.                 if ( result == noErr )
  140.                 {
  141.                     /* Set up the globals we need to access from the recursive routine. */
  142.                     theGlobals.iterateFilter = iterateFilter;
  143.                     theGlobals.cPB.hFileInfo.ioNamePtr = (StringPtr)&theGlobals.itemName;
  144.                     theGlobals.cPB.hFileInfo.ioVRefNum = theVRefNum;
  145.                     theGlobals.itemName[0] = 0;
  146.                     theGlobals.result = noErr;
  147.                     theGlobals.quitFlag = false;
  148.                     theGlobals.maxLevels = maxLevels;
  149.                     theGlobals.currentLevel = 0;    /* start at level 0 */
  150.                     theGlobals.yourDataPtr = yourDataPtr;
  151.                 
  152.                     /* Here we go into recursion land... */
  153.                     IterateDirectoryLevel(theDirID, &theGlobals);
  154.                     
  155.                     result = theGlobals.result;    /* set the result */
  156.                 }
  157.             }
  158.             else
  159.             {
  160.                 result = dirNFErr;    /* a file was passed instead of a directory */
  161.             }
  162.         }
  163.     }
  164.     else
  165.     {
  166.         result = paramErr;    /* iterateFilter was NULL */
  167.     }
  168.     
  169.     return ( result );
  170. }
  171.  
  172. /*****************************************************************************/
  173.  
  174. pascal    OSErr    FSpIterateDirectory(const FSSpec *spec,
  175.                                     unsigned short maxLevels,
  176.                                     IterateFilterProcPtr iterateFilter,
  177.                                     void *yourDataPtr)
  178. {
  179.     return ( IterateDirectory(spec->vRefNum, spec->parID, (StringPtr)spec->name,
  180.                         maxLevels, iterateFilter, yourDataPtr) );
  181. }
  182.  
  183. /*****************************************************************************/
  184.